package tor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.asn1.pkcs.RSAPrivateKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.io.pem.PemReader; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import java.security.Security; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; import java.util.HashMap; import java.util.Map; /** * Created by gho on 03/08/14. */ public class TorServerSocket extends TorSocket { final static Logger log = LogManager.getLogger(); static X509Certificate identityCert; static RSAPublicKey identityPubKey; static RSAPrivateKey identityPrivKey; static X509Certificate linkCert; static X509Certificate authCert; /** * Sets up port listener * * @param localPort * @throws IOException */ public TorServerSocket(int localPort) throws IOException, NoSuchAlgorithmException, CertificateEncodingException { Security.addProvider(new BouncyCastleProvider()); SSLContext sc; if (!new File("keys/keystore.jks").exists()) { log.fatal("keys/keystore.jks not found. Make sure you run certgen.sh in keys/"); System.exit(1); } System.setProperty("javax.net.ssl.keyStore", "keys/keystore.jks"); System.setProperty("javax.net.ssl.keyStorePassword", "123456"); loadKeys(); // connect ServerSocket listenSocket = SSLServerSocketFactory.getDefault().createServerSocket(localPort); while (true) { Socket client = listenSocket.accept(); System.out.println("New client connection from " + client.getRemoteSocketAddress()); new TorServerSocket(client); } } /** * Called for each new client connection - instantiating a new object * * @param client * @throws IOException */ private TorServerSocket(final Socket client) throws IOException { this.sslsocket = (javax.net.ssl.SSLSocket) client; in = client.getInputStream(); out = client.getOutputStream(); new Thread(new Runnable() { @Override public void run() { receiveHandlerLoop(); } }).start(); } public void loadKeys() { try { FileInputStream idCertIS = new FileInputStream(new File("keys/identity.crt")); FileInputStream linkCertIS = new FileInputStream(new File("keys/link.crt")); FileInputStream authCertIS = new FileInputStream(new File("keys/auth.crt")); CertificateFactory cf = null; cf = CertificateFactory.getInstance("X.509"); identityCert = (X509Certificate) cf.generateCertificate(idCertIS); log.info("Our Identity Cert Digest: " + Hex.toHexString(TorCrypto.getSHA1().digest(TorCrypto.publicKeyToASN1((RSAPublicKey) identityCert.getPublicKey())))); linkCert = (X509Certificate) cf.generateCertificate(linkCertIS); log.info("Our Link Cert Digest: " + Hex.toHexString(TorCrypto.getSHA1().digest(TorCrypto.publicKeyToASN1((RSAPublicKey) linkCert.getPublicKey())))); authCert = (X509Certificate) cf.generateCertificate(authCertIS); log.info("Our Auth Cert Digest: " + Hex.toHexString(TorCrypto.getSHA1().digest(TorCrypto.publicKeyToASN1((RSAPublicKey) authCert.getPublicKey())))); identityPubKey = (RSAPublicKey) identityCert.getPublicKey(); FileReader in = new FileReader("keys/identity.key"); identityPrivKey = RSAPrivateKey.getInstance(new PemReader(in).readPemObject().getContent()); } catch (CertificateException | IOException e) { log.error("Unable to load server public key"); System.exit(1); } } public void sendCertsCell() throws IOException { HashMap<Integer, byte[]> certs = new HashMap<>(); try { certs.put(1, linkCert.getEncoded()); certs.put(2, identityCert.getEncoded()); certs.put(3, authCert.getEncoded()); } catch (CertificateEncodingException e) { log.fatal(e); System.exit(1); return; } ByteBuffer buf = ByteBuffer.allocate(4096); buf.put((byte) certs.size()); for (Map.Entry<Integer, byte[]> cert : certs.entrySet()) { buf.put((byte) cert.getKey().intValue()); buf.putShort((short) cert.getValue().length); buf.put(cert.getValue()); } buf.flip(); byte certsCell[] = new byte[buf.limit()]; buf.get(certsCell); sendCell(0, Cell.CERTS, certsCell); } public void receiveHandlerLoop() { while(true) { try { Cell c = recvCell(); switch (c.cmdId) { case Cell.VERSIONS: sendCell(0, Cell.VERSIONS, new byte[]{00, 03, 00, 04}); ByteBuffer verBuf = ByteBuffer.wrap(c.payload); for (int i = 0; i < c.payload.length; i+=2) { int offeredVer = verBuf.getShort(); if(offeredVer <= PROTOCOL_VERSION_MAX && offeredVer > PROTOCOL_VERSION) PROTOCOL_VERSION = offeredVer; } log.info("Negotiated protocol version: " + PROTOCOL_VERSION); sendCertsCell(); sendNetInfo(); continue; case Cell.CREATED: log.error("Got created cell - not impl!"); continue; case Cell.DESTROY: log.info("Destroy cell reason {}", TorCircuit.DESTROY_ERRORS[c.payload[0]]); continue; default: log.info("[UNHANDLED] Got cell cmd " + c.cmdId); continue; } } catch (IOException e) { log.error("Closing tor client connection: " + e); break; } } } }